package com.example.system.service.question.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.common.core.constants.Constants;
import com.example.common.core.enums.ResultCode;
import com.example.common.core.exception.ServiceException;
import com.example.system.domain.question.Question;
import com.example.system.domain.question.dto.QuestionAddDTO;
import com.example.system.domain.question.dto.QuestionEditDTO;
import com.example.system.domain.question.dto.QuestionQueryDTO;
import com.example.system.domain.question.es.QuestionES;
import com.example.system.domain.question.vo.QuestionDetailVO;
import com.example.system.domain.question.vo.QuestionVO;
import com.example.system.elasticsearch.QuestionRepository;
import com.example.system.manger.QuestionCacheManager;
import com.example.system.mapper.question.QuestionMapper;
import com.example.system.service.question.IQuestionService;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
public class QuestionServiceImpl implements IQuestionService {


    @Autowired
    private QuestionMapper questionMapper;
    @Autowired
    private QuestionRepository questionRepository;
    @Autowired
    private QuestionCacheManager questionCacheManager;

    //获取题目列表
    @Override
    public List<QuestionVO> list(QuestionQueryDTO questionQueryDTO) {
        //判断一下excludeId是否为空，如果为空则不需要处理
        String excludeIdStr =questionQueryDTO.getExcludeIdStr();
        if (StrUtil.isNotEmpty(excludeIdStr)) {
            //通过定义好的分隔符，解析出前端传来的所有id
            String[] excludeIdArr = excludeIdStr.split(Constants.SPLIT_SEM);
            Set<Long> excludeIdSet = Arrays.stream(excludeIdArr)
                    .map(Long::valueOf).collect(Collectors.toSet());
            questionQueryDTO.setExcludeIdSet(excludeIdSet);
        }
        //设置自动分页查询
        PageHelper.startPage(questionQueryDTO.getPageNum(), questionQueryDTO.getPageSize());
        //从数据库中查询题目列表
        return questionMapper.selectQuestionList(questionQueryDTO);
    }

    //获取题目详情
    @Override
    public QuestionDetailVO detail(Long questionId) {
        Question question = isNotEmptyQuestion(questionId);
        //如果查询出来了，转换对象
        QuestionDetailVO questionDetailVO = new QuestionDetailVO();
        BeanUtils.copyProperties(question, questionDetailVO);
        return questionDetailVO;
    }

    //添加题目
    @Override
    public int add(QuestionAddDTO questionAddDTO) {
        //验证参数合法性的
        //检查默认代码块是否合法
        isDefaultCodeWrappedInSolutionClass(questionAddDTO.getDefaultCode());
        //验证代码测试用例是否合法
        validateQuestionCase(questionAddDTO.getQuestionCase());
        //检验main函数是否合法
        validateMainFunction(questionAddDTO.getMainFuc());
        //判断题目标题重复性
        //根据标题从数据库中查询相应的题目
        List<Question> questionList = questionMapper.selectList(new LambdaQueryWrapper<Question>()
                .eq(Question::getTitle,questionAddDTO.getTitle()));
        //如果能查到该题目，说明重复了
        if (CollectionUtil.isNotEmpty(questionList))   {
            throw  new ServiceException(ResultCode.FAILED_QUESTION_TITILE_EXISTS);
        }
        //对象转换
        Question question = new Question();
        BeanUtils.copyProperties(questionAddDTO, question);
        //把题目存入数据库
        Integer result = questionMapper.insert(question);
        if (result > 0) {
            //同步插入到es中
            QuestionES questionES = new QuestionES();
            BeanUtils.copyProperties(question, questionES);
            questionRepository.save(questionES);
            //同步redis维护的题目顺序中,为后续的上一题下一题的功能服务
            questionCacheManager.addCache(question.getQuestionId());
        }
        return result;
    }

    //编辑题目
    @Override
    public int edit(QuestionEditDTO questionEditDTO) {
        //验证参数合法性的
        //检查默认代码块是否合法
        isDefaultCodeWrappedInSolutionClass(questionEditDTO.getDefaultCode());
        //验证代码测试用例是否合法
        validateQuestionCase(questionEditDTO.getQuestionCase());
        //检验main函数是否合法
        validateMainFunction(questionEditDTO.getMainFuc());

        //先查询一下，这个要编辑的题目是否存在
        Question question = isNotEmptyQuestion(questionEditDTO.getQuestionId());
        //存在则直接转为question对象
        BeanUtils.copyProperties(questionEditDTO, question);
        //把es的数据也同步更新了
        QuestionES questionES = new QuestionES();
        BeanUtils.copyProperties(question, questionES);
        //es也同步更新
        questionRepository.save(questionES);
        return questionMapper.updateById(question);
    }

    //删除题目
    @Override
    public int delete(Long questionId) {
        //删除之前先检查该题目是否存在
        isNotEmptyQuestion(questionId);
        //es也同步删除
        questionRepository.deleteById(questionId);
        //redis维护的题目顺序也同步删除
        questionCacheManager.deleteCache(questionId);
        return questionMapper.deleteById(questionId);
    }


    //检查题目是否存在，如果存在则返回题目对象
    private Question isNotEmptyQuestion(Long questionId) {
        //先查询一下，这个要编辑的题目是否存在
        Question question = questionMapper.selectById(questionId);
        if (question == null){
            throw  new ServiceException(ResultCode.FAILED_NOT_EXISTS);
        }
        return question;
    }


    // 验证 defaultCode 是否被 class Solution 类封装
    private void isDefaultCodeWrappedInSolutionClass(String defaultCode) {
        // 使用正则表达式检查 defaultCode 是否包含 "class Solution {" 和 "}"
        // 使用正则表达式检查 defaultCode 是否包含 "class Solution {" 和 "}"
        String classSolutionPattern = "\\s*class\\s+Solution\\s*\\{.*\\}\\s*";
        Pattern pattern = Pattern.compile(classSolutionPattern, Pattern.DOTALL);
        Matcher matcher = pattern.matcher(defaultCode.trim());
        if (!matcher.matches()){
            throw new ServiceException(ResultCode.FAILED_QUESTION_DEFAULTCODE_ERROR);
        }
    }


    private void validateQuestionCase(String questionCase) {
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            JsonNode rootNode = objectMapper.readTree(questionCase);
            // 验证是否为数组
            if (!(rootNode instanceof ArrayNode)) {
                throw new ServiceException(ResultCode.FAILED_QUESTION_QUESTIONCASE_ERROR);
            }
            ArrayNode arrayNode = (ArrayNode) rootNode;
            // 遍历数组中的每个元素
            for (JsonNode node : arrayNode) {
                // 验证每个元素是否为对象
                if (!(node instanceof ObjectNode)) {
                    throw new ServiceException(ResultCode.FAILED_QUESTION_QUESTIONCASE_ERROR);
                }
                ObjectNode objectNode = (ObjectNode) node;
                // 验证对象中是否包含input和output属性
                if (!objectNode.has("input") || !objectNode.has("output")) {
                    throw new ServiceException(ResultCode.FAILED_QUESTION_QUESTIONCASE_ERROR);
                }
                // 由于input和output的值可以是任何有效的JSON类型，这里不再进行类型检查
            }
        } catch (IOException e) {
            // JSON解析异常，格式不正确
            throw new ServiceException(ResultCode.FAILED_QUESTION_QUESTIONCASE_ERROR);
        }
    }

    private void validateMainFunction(String code) {
        // 使用正则表达式匹配标准的main函数格式，允许换行，并且允许main函数体中有内容或为空
        String regex = "public\\s+static\\s+void\\s+main\\s*\\(\\s*String\\s*\\[\\]\\s+args\\s*\\)\\s*\\{.*\\}\\s*";
        Pattern pattern = Pattern.compile(regex, Pattern.DOTALL);
        Matcher matcher = pattern.matcher(code.trim());
        // 检查是否匹配main函数
        if (!matcher.matches()){
            throw new ServiceException(ResultCode.FAILED_QUESTION_MAIN_ERROR);
        }
    }

}

